#pragma once

#include <pthread.h>
#include <vector>
#include <string>
#include <queue>
#include <mutex>
#include "../thread/Thread.h"
#include "../LockGuard/LockGuard.hpp"

using namespace ThreadNs;

template <typename T>
class ThreadPool;

template <typename Fn>
struct ThreadData
{
    ThreadPool<Fn> *thread_pool;
    std::string name;

    ThreadData(ThreadPool<Fn> *tp, std::string thread_name) :thread_pool(tp), name(thread_name) {}
};

const size_t default_thread_pool_size = 5;

template <typename T>
class ThreadPool
{
    
    ThreadPool(const ThreadPool &) = delete;
    void operator=(const ThreadPool &) = delete;

private:
    static void* handTask(void* args)
    {
        ThreadData<T>* td = static_cast<ThreadData<T>*>(args);
        while (true)
        {
            //tp->lockQueue();
            T t;
            {
                LockGuard lock(td->thread_pool->mutex());
                while (td->thread_pool->isQueueEmpty())
                {
                    td->thread_pool->threadWait();
                }
                t = td->thread_pool->pop();
            }
            //tp->unlockQueue();
            t();
            // std::cout << "处理数据为 " << t() << std::endl;
        }
        delete td;
        td = nullptr;
        return nullptr;
    }

private:

    pthread_mutex_t *mutex() { return &_mutex; }
    void lockQueue() { pthread_mutex_lock(&_mutex); }
    void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    bool isQueueEmpty() { return _task_queue.empty(); }
    void threadWait() { pthread_cond_wait(&_cond, &_mutex); }
    T pop()
    {
        T ret = _task_queue.front();
        _task_queue.pop();
        return ret;
    }

    /// @brief 构建一个线程池
    /// @param size 线程池大小
    ThreadPool(const size_t &size = default_thread_pool_size) : _thread_size(size)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        _threads.resize(_thread_size);
        for (auto& th : _threads)
        {
            th = new Thread();
        }
    }

public:

    static ThreadPool<T> *getInstance()
    {
        if (_thread_pool_ptr == nullptr)
        {
            _lock.lock();
            if (_thread_pool_ptr == nullptr)
            {
                _thread_pool_ptr = new ThreadPool<T>();
            }
            _lock.unlock();
        }
        return const_cast<ThreadPool<T> *>(_thread_pool_ptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);

        for (auto& thread : _threads)
            delete thread;
    }

    /// @brief 加入任务
    /// @param in_val 要加入的任务
    void push(const T& in_val)
    {
        LockGuard lock(&_mutex);
        _task_queue.push(in_val);
        pthread_cond_signal(&_cond);
    }

    /// @brief 运行线程池中的任务
    void run()
    {
        for (const auto &th : _threads)
        {
            ThreadData<T> *td = new ThreadData<T>(this, th->name());
            th->start(handTask, td);
            // th->start(handTask, this);
        }
    }

private:

    size_t _thread_size;//线程池大小
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;//条件变量
    std::vector<Thread*> _threads;
    std::queue<T> _task_queue; //任务队列

public:
    static volatile ThreadPool<T> *_thread_pool_ptr;
    static std::mutex _lock;
};

template <typename T>
volatile ThreadPool<T> *ThreadPool<T>::_thread_pool_ptr = nullptr;

template <typename T>
std::mutex ThreadPool<T>::_lock;